home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-09-08 | 32.2 KB | 1,238 lines |
- Newsgroups: comp.sources.misc
- From: Gary Mills <mills@ccu.umanitoba.ca>
- Subject: v22i097: mailclean - Unix mail spool management package, Part01/01
- Message-ID: <1991Sep6.040355.13740@sparky.IMD.Sterling.COM>
- X-Md4-Signature: e87929cf3c1d83b3c4c7ccaebb79fe5c
- Date: Fri, 6 Sep 1991 04:03:55 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: Gary Mills <mills@ccu.umanitoba.ca>
- Posting-number: Volume 22, Issue 97
- Archive-name: mailclean/part01
- Environment: SunOS
-
- This is the mailclean package and is described below in more detail in
- the README and the man pages. Its purpose is to exercise control over
- the disk space used for the mail spool. I investigated the feasiblity
- of using the Berkeley disk quota for this purpose, and determined that
- it was not suitable. Mailclean is a practical alternative. It's
- designed to control the size of user's mailboxes in a nice way, warning
- them before action may be taken, and notifying them afterwards. Any
- administrator with a reasonable knowledge of the mail system should
- be able to install and configure it.
-
- Mailclean can also be retreived via anonymous ftp from ccu.umanitoba.ca
- as /pub/mailclean.tar.Z. It has only run on SunOS so far, but I wrote
- it to be portable. It should be usable on any Unix system that uses the
- normal Unix mail. I am the author of the mailclean package and I place
- no restrictions on it, although I would like to know if others make
- changes to it. I will integrate patches if people send them to me.
-
- -Gary Mills- -Networking Group- -U of M Computer Services-
- ==================
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # README
- # Makefile
- # defs.h
- # mailclean.c
- # mailsize.c
- # mailclean.8
- # mailsize.1
- # policy
- # trunc.msg
- # This archive created: Wed Sep 4 21:37:48 CDT 1991
- # By: mills (Gary Mills)
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'README'" '( 1555 characters)'
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- sed 's/^X//' << \SHAR_EOF > 'README'
- X
- XMailclean and mailsize comprise a mail spool management package for
- Xunix. They restrict the amount of spool space available to users,
- Xbut do it in a nicer way than disk quota would do. They are very
- Xconfigurable, taking parameters from a policy file.
- X
- XMailclean is intended to be run regularly from cron. It produces a
- Xreport on standard output. It can truncate oversize mailboxes,
- Xsaving old mail to a temporary file, and notifying the owner by mail.
- XIt does this in a careful manner, using the same locking mechanism
- Xas bin/mail and ucb/mail. It can also remove or report old mailboxes,
- Xstray files, or unsafe files in the spool directory.
- X
- XMailsize is intended to be run by the user during login. It produces
- Xa warning about the size of the mailbox, in the manner of ``quota''
- Xor ``quota -v''. There are several ways to arrange for it to be run
- Xduring login. It can be added to a global profile or login file.
- XAlternatively, mailsize can replace ``quota'', either completely,
- Xor only as the command invoked by ``login''.
- X
- XThe policy file, nominally /etc/policy, is a common location for
- Xparameters, and is designed to be easily parsed by C programs or
- Xshell scripts. It could be extended for other similar purposes.
- X
- XThese programs have so far only run under SunOS 4.1.1, but they should
- Xbe reasonably portable to other unix mail systems. If you need to
- Xmake source modifications for other systems, please send me the diffs,
- Xand I will merge them with my source.
- X
- XGary Mills <mills@ccu.umanitoba.ca>
- XUniversity of Manitoba
- XWinnipeg, Canada
- X
- SHAR_EOF
- if test 1555 -ne "`wc -c < 'README'`"
- then
- echo shar: "error transmitting 'README'" '(should have been 1555 characters)'
- fi
- fi
- echo shar: "extracting 'Makefile'" '( 1011 characters)'
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- sed 's/^X//' << \SHAR_EOF > 'Makefile'
- XSHELL = /bin/sh
- XPACKAGE = README Makefile defs.h mailclean.c mailsize.c \
- X mailclean.8 mailsize.1 policy trunc.msg
- X
- X# the compiler
- X#CC = /bin/cc
- XCC = /usr/5bin/cc
- X
- X# compiler flags
- X#CFLAGS =
- XCFLAGS = '-DPFILE="/usr/local/etc/policy"'
- X
- X# destinaton for administrative commands
- XEBIN = /usr/local/etc
- X
- X# destination for user commands
- XBIN = /usr/local/bin
- X
- X# man page directory with last char omitted
- XMAN = /usr/local/man/man
- X
- Xall: mailclean mailsize
- X
- Xmailclean: mailclean.c defs.h Makefile
- X $(CC) $(CFLAGS) -o mailclean mailclean.c
- Xmailsize: mailsize.c defs.h Makefile
- X $(CC) $(CFLAGS) -o mailsize mailsize.c
- X
- Xinstall: mailclean
- X install -c -o bin -g bin -m 0755 mailclean $(EBIN)
- X install -c -o bin -g bin -m 0755 mailsize $(BIN)
- X
- Xman: mailclean.8 mailsize.1
- X install -c -m 0444 mailclean.8 $(MAN)8/mailclean.8
- X install -c -m 0444 mailsize.1 $(MAN)1/mailsize.1
- X
- Xclean:
- Xclobber: clean
- X -rm -f mailclean mailsize
- X
- Xshar: $(PACKAGE)
- X shar $(PACKAGE) > mailclean.shar
- X
- Xtar: $(PACKAGE)
- X tar cf mailclean.tar $(PACKAGE)
- SHAR_EOF
- if test 1011 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: "error transmitting 'Makefile'" '(should have been 1011 characters)'
- fi
- fi
- echo shar: "extracting 'defs.h'" '( 919 characters)'
- if test -f 'defs.h'
- then
- echo shar: "will not over-write existing file 'defs.h'"
- else
- sed 's/^X//' << \SHAR_EOF > 'defs.h'
- X/* defs.h: definitions for mailclean and mailsize */
- X
- X#define VERSION "version 1.0"
- X
- X/* policy file */
- X#ifndef PFILE
- X#define PFILE "/etc/policy"
- X#endif
- X
- X/* mail spool directory */
- X#ifndef SPOOL
- X#define SPOOL "/usr/spool/mail"
- X#endif
- X
- X/* directory for saved old mail */
- X#ifndef OLDDIR
- X#define OLDDIR "/var/tmp"
- X#endif
- X
- X/* mail command */
- X#define MAILCMD "/bin/mail %s"
- X
- X/* if invoked with this name, mailsize will run quota */
- X#define QNAME "Quota"
- X
- X/* path to the real quota command */
- X#define QPATH "/usr/ucb/quota"
- X
- X#define PLEN 256
- X#define FALSE 0
- X#define TRUE 1
- X
- X#define SIZ_TR 0
- X#define AGE_RM 1
- X#define STR_RM 2
- X#define SIZ_RP 3
- X#define NRE_RP 4
- X#define STR_RP 5
- X#define SIZ_MS 6
- X#define SIZ_WA 7
- X#define STR_SC 8
- X
- Xstruct pmap {
- X char *pm_verb;
- X int pm_case;
- X};
- X
- Xstruct smap {
- X char *sm_nam;
- X char *sm_val;
- X};
- X
- Xstruct store {
- X struct store *se_link;
- X char se_type;
- X char se_str[1];
- X};
- X
- X/**/
- SHAR_EOF
- if test 919 -ne "`wc -c < 'defs.h'`"
- then
- echo shar: "error transmitting 'defs.h'" '(should have been 919 characters)'
- fi
- fi
- echo shar: "extracting 'mailclean.c'" '( 14403 characters)'
- if test -f 'mailclean.c'
- then
- echo shar: "will not over-write existing file 'mailclean.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'mailclean.c'
- X/* mailclean.c: mail spool cleanup policy enforcer */
- X/* Author: Gary Mills <mills@ccu.umanitoba.ca> */
- X
- X#include <stdio.h>
- X#include <stdlib.h>
- X#include <string.h>
- X#include <errno.h>
- X#include <time.h>
- X#include <dirent.h>
- X#include <pwd.h>
- X#include <ctype.h>
- X#include <signal.h>
- X#include <utime.h>
- X#include <malloc.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/file.h>
- X
- X#include "defs.h"
- X
- Xchar usage[] = "Usage: %s [-y]\n";
- Xint siz_tr_high = 0, siz_tr_low = 0;
- Xint age_rm_days = 0;
- Xint str_rm = FALSE;
- Xint siz_rp_high = 0;
- Xint nre_rp = FALSE;
- Xint str_rp = FALSE;
- Xint str_sc = FALSE;
- Xint siz_wa_high = 0;
- Xchar *siz_ms = NULL;
- Xint yopt = FALSE; /* "yes" option */
- Xint intflag = FALSE;
- X
- Xchar mbname[9];
- Xchar oldfile[PLEN];
- Xchar highsize[9], lowsize[9], warnsize[9];
- Xchar erline[PLEN];
- Xchar msname[PLEN];
- Xchar *cmdname;
- Xlong curtime;
- X
- X/* policy subset interpreted here */
- Xstruct pmap policy[] = {
- X { "mail-size-truncate", SIZ_TR },
- X { "mail-age-remove", AGE_RM },
- X { "mail-stray-remove", STR_RM },
- X { "mail-size-report", SIZ_RP },
- X { "mail-unsafe-report", NRE_RP },
- X { "mail-stray-report", STR_RP },
- X { "mail-size-message", SIZ_MS },
- X { "mail-size-warn", SIZ_WA },
- X { "mail-stray-script", STR_SC },
- X { NULL, 0 }
- X};
- X
- X/* symbols for notification message */
- Xstruct smap symtab[] = {
- X { "mailbox", mbname },
- X { "oldfile", oldfile },
- X { "hsize", highsize },
- X { "lsize", lowsize },
- X { "wsize", warnsize },
- X { "", "\\" },
- X { NULL, NULL },
- X};
- X
- Xmain(argc, argv) int argc; char *argv[]; {
- X char *spool, *op;
- X struct dirent *curent;
- X struct passwd *curpass;
- X DIR *dpt;
- X struct stat curstat;
- X char owner[9];
- X int report, size, age, nuid;
- X char *reason, *action;
- X int n;
- X extern void intcatch();
- X extern struct store *savestr();
- X
- X /* parse arguments */
- X cmdname = ( cmdname = strrchr(argv[0], '/') ) ? ++cmdname : argv[0];
- X while ( ++argv, --argc > 0 && *argv[0] == '-' ) {
- X for ( op = argv[0] + 1; *op; ++op ) {
- X switch ( *op ) {
- X case 'y':
- X yopt = TRUE;
- X break;
- X default:
- X (void) fprintf(stderr, usage, cmdname);
- X exit(1);
- X }
- X }
- X }
- X if ( argc > 0 ) {
- X (void) fprintf(stderr, usage, cmdname);
- X exit(1);
- X }
- X
- X /* initialize */
- X (void) time(&curtime);
- X if ( getpolicy() != 0 )
- X exit(1);
- X prheader();
- X (void) sprintf(highsize, "%d", siz_tr_high);
- X (void) sprintf(lowsize, "%d", siz_tr_low);
- X (void) sprintf(warnsize, "%d", siz_wa_high);
- X spool = SPOOL;
- X if ( signal(SIGHUP, SIG_IGN) != SIG_IGN )
- X (void) signal(SIGHUP, intcatch);
- X if ( signal(SIGINT, SIG_IGN) != SIG_IGN )
- X (void) signal(SIGINT, intcatch);
- X if ( signal(SIGQUIT, SIG_IGN) != SIG_IGN )
- X (void) signal(SIGQUIT, intcatch);
- X (void) signal(SIGTERM, intcatch);
- X (void) umask(0066);
- X if ( chdir(spool) != 0 ) {
- X (void) sprintf(erline, "%s: Cannot chdir to %s", cmdname, spool);
- X perror(erline);
- X exit(1);
- X }
- X if ( ( dpt = opendir(spool) ) == NULL ) {
- X (void) sprintf(erline, "%s: Cannot diropen %s", cmdname, spool);
- X perror(erline);
- X exit(1);
- X }
- X
- X /* run through the directory entries */
- X while ( errno = 0, curent = readdir(dpt) ) {
- X if ( intflag ) {
- X (void) fprintf(stderr, "%s: Caught a signal", cmdname);
- X exit(1);
- X }
- X
- X /* skip special entries */
- X if ( strcmp(curent->d_name,".") == 0 || strcmp(curent->d_name,"..") == 0 )
- X continue;
- X
- X /*collect information */
- X if ( stat(curent->d_name, &curstat) != 0 ) {
- X (void) sprintf(erline, "%s: Cannot stat %s", cmdname, curent->d_name);
- X perror(erline);
- X exit(1);
- X }
- X size = curstat.st_size / 1024L;
- X age = ( curtime - curstat.st_atime ) / ( 24 * 60 * 60 );
- X
- X /* skip lock and temp files */
- X if ( ( n = strlen(curent->d_name) ) > 5 && age < 2 &&
- X strcmp(curent->d_name + n - 5, ".lock") == 0 )
- X continue;
- X if ( n > 6 && curstat.st_size == 0 && age < 1 &&
- X istmpnam(curent->d_name + n - 6) )
- X continue;
- X if ( curpass = getpwnam(curent->d_name) ) {
- X nuid = curpass->pw_uid;
- X }
- X else {
- X nuid = -99999;
- X }
- X if ( curpass = getpwuid(curstat.st_uid) ) {
- X (void) strcpy(owner, curpass->pw_name);
- X }
- X else {
- X (void) sprintf(owner, "%d", (int) curstat.st_uid);
- X }
- X report = FALSE;
- X reason = action = "";
- X
- X /* classify files, perform action, and report */
- X if ( ( curstat.st_mode & S_IFMT ) != S_IFREG || curstat.st_nlink > 1 ) {
- X reason = "unsafe";
- X if ( nre_rp ) {
- X report = TRUE;
- X }
- X }
- X else if ( curstat.st_uid != nuid ) {
- X reason = "stray";
- X if ( str_rm ) {
- X if ( doremove(curent->d_name) != 0 )
- X exit(1);
- X report = TRUE;
- X action = "removed";
- X }
- X else if ( str_sc ) {
- X if ( savestr('r', curent->d_name) == NULL )
- X exit(1);
- X report = TRUE;
- X action = "scripted";
- X }
- X else if ( str_rp ) {
- X report = TRUE;
- X }
- X }
- X else if ( age > age_rm_days ) {
- X reason = "age";
- X if ( doremove(curent->d_name) != 0 )
- X exit(1);
- X report = TRUE;
- X action = "removed";
- X }
- X else if ( size > siz_tr_high ) {
- X reason = "size";
- X (void) strcpy(mbname, curent->d_name);
- X if ( dotrunc(curent->d_name, &curstat) != 0 )
- X exit(1);
- X report = TRUE;
- X action = "truncated";
- X }
- X else if ( size > siz_rp_high ) {
- X reason = "size";
- X report = TRUE;
- X }
- X if ( report )
- X (void) printf("%-16s%-12s%6d%8d %-16s%s\n", curent->d_name,
- X owner, size, age, reason, action);
- X }
- X if ( errno ) {
- X (void) sprintf(erline, "%s: Readdir failed", cmdname);
- X perror(erline);
- X exit(1);
- X }
- X (void) closedir(dpt);
- X (void) printf("\nReport completed\n\n");
- X prscript(spool);
- X exit(0);
- X /*NOTREACHED*/
- X}
- X
- X/* getpolicy: interpret the policy file */
- Xint getpolicy() {
- X char pline[PLEN], pverb[PLEN];
- X FILE *pfp;
- X char *pfile, *pt;
- X struct pmap *pp;
- X int n1, n2;
- X
- X pfile = PFILE;
- X if ( ( pfp = fopen(pfile, "r") ) == NULL ) {
- X (void) sprintf(erline, "%s: Cannot open %s", cmdname, pfile);
- X perror(erline);
- X return 1;
- X }
- X else {
- X while ( fgets(pline, PLEN, pfp) ) {
- X if ( ( pt = strchr(pline, '#') ) != NULL )
- X *pt = '\0';
- X if ( sscanf(pline, "%s", pverb) == 1 ) {
- X for ( pp = &policy[0]; pp->pm_verb; ++pp ) {
- X if ( strcmp(pverb, pp->pm_verb) == 0 ) {
- X switch (pp->pm_case) {
- X case SIZ_TR:
- X if ( sscanf(pline, "%*s%d%d", &n1, &n2) == 2 ) {
- X siz_tr_high = n1;
- X siz_tr_low = n2;
- X }
- X break;
- X case AGE_RM:
- X if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
- X age_rm_days = n1;
- X }
- X break;
- X case STR_RM:
- X str_rm = TRUE;
- X break;
- X case SIZ_RP:
- X if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
- X siz_rp_high = n1;
- X }
- X break;
- X case NRE_RP:
- X nre_rp = TRUE;
- X break;
- X case STR_RP:
- X str_rp = TRUE;
- X break;
- X case STR_SC:
- X str_sc = TRUE;
- X break;
- X case SIZ_MS:
- X if ( sscanf(pline, "%*s%s", msname) == 1 ) {
- X siz_ms = msname;
- X }
- X break;
- X case SIZ_WA:
- X if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
- X siz_wa_high = n1;
- X }
- X break;
- X }
- X break;
- X }
- X }
- X }
- X }
- X (void) fclose(pfp);
- X }
- X return 0;
- X}
- X
- X/* prheader: print the report header */
- Xprheader() {
- X
- X (void) printf("Mail Spool Cleanup Report:\t\t%s\n", ctime(&curtime));
- X (void) printf("\nPolicy in effect:\n");
- X if ( siz_tr_high > 0 )
- X (void) printf("\tTruncate from %d to %d kbytes\n", siz_tr_high, siz_tr_low);
- X if ( siz_ms )
- X (void) printf("\tSend message from %s\n", siz_ms);
- X if ( age_rm_days > 0 )
- X (void) printf("\tRemove older than %d days\n", age_rm_days);
- X if ( str_rm )
- X (void) printf("\tRemove stray files\n");
- X if ( str_sc )
- X (void) printf("\tScript stray files\n");
- X if ( siz_rp_high > 0 )
- X (void) printf("\tReport larger than %d kbytes\n", siz_rp_high);
- X if ( nre_rp )
- X (void) printf("\tReport unsafe files\n");
- X if ( str_rp )
- X (void) printf("\tReport stray files\n");
- X (void) printf("\nMode:");
- X (void) printf( (!yopt) ? " simulated" : " actual");
- X (void) printf("\n\n\n%-16s%-12s%6s%8s %-16s%s\n\n", "NAME", "OWNER",
- X "SIZE", "AGE", "REASON", "ACTION");
- X}
- X
- X/* doremove: remove a spool file */
- Xdoremove(file) char *file; {
- X
- X if ( yopt && unlink(file) != 0 ) {
- X (void) sprintf(erline, "%s: Cannot unlink %s", cmdname, file);
- X perror(erline);
- X return 1;
- X }
- X return 0;
- X}
- X
- X/* dotrunc: truncate a spool file */
- Xstatic int serial = 0;
- Xstatic char cset[] =
- X "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+";
- X
- Xdotrunc(file, st) char *file; struct stat *st; {
- X char *olddir;
- X char *p1, *p2;
- X struct utimbuf ut;
- X char vary[3];
- X char temfile[PLEN];
- X char line[PLEN];
- X char tline[PLEN];
- X char gatefile[16];
- X char lockfile[16];
- X char cline[64];
- X long len, lim;
- X int n, rc;
- X FILE *oldfp, *tmpfp, *mailfp;
- X FILE *msfp, *pifp;
- X extern FILE *fmkstemp();
- X extern char *subst();
- X
- X if ( !yopt ) return 0;
- X olddir = OLDDIR;
- X
- X /* build file names */
- X vary[0] = cset[ ( serial % ( 64 * 64 ) ) / 64 ];
- X vary[1] = cset[ serial % 64 ];
- X vary[2] = '\0';
- X ++serial;
- X (void) sprintf(oldfile, "%s/%sXXXXXX", olddir, vary);
- X (void) sprintf(temfile, "/tmp/%sXXXXXX", vary);
- X (void) sprintf(gatefile, "%sXXXXXX", vary);
- X (void) sprintf(lockfile, "%s.lock", file);
- X
- X /* create file to save old mail */
- X if ( ( oldfp = fmkstemp(oldfile) ) == NULL )
- X return 1;
- X rc = 0;
- X
- X /* create temp file */
- X if ( ( tmpfp = fmkstemp(temfile) ) == NULL )
- X rc = 1;
- X if ( !rc ) {
- X (void) unlink(temfile);
- X
- X /* create temp file for locking */
- X if ( ( n = mkstemp(gatefile) ) < 0 ) {
- X (void) sprintf(erline, "%s: Cannot create %s", cmdname, gatefile);
- X perror(erline);
- X rc = 1;
- X }
- X if ( !rc ) {
- X (void) close(n);
- X n = 0;
- X
- X /* create lock file */
- X while ( link(gatefile, lockfile) != 0 ) {
- X if ( errno != EEXIST || n > 60 ) {
- X (void) sprintf(erline, "%s: Cannot create lock %s",
- X cmdname, lockfile);
- X perror(erline);
- X rc = 1;
- X break;
- X }
- X (void) sleep(5);
- X n += 5;
- X }
- X (void) unlink(gatefile);
- X if ( !rc ) {
- X
- X /* open the mailbox */
- X if ( ( mailfp = fopen(file, "r+") ) == NULL ) {
- X (void) sprintf(erline, "%s: Cannot open %s", cmdname, file);
- X perror(erline);
- X rc = 1;
- X }
- X if ( !rc ) {
- X
- X /* lock with flock, too */
- X (void) flock(fileno(mailfp), LOCK_EX);
- X n = 0;
- X len = 0L;
- X lim = st->st_size - (siz_tr_low * 1024);
- X
- X /* copy with truncation */
- X while ( fgets(line, PLEN, mailfp) ) {
- X len += strlen(line);
- X if ( n == 0 && len > lim &&
- X strncmp(line, "From ", 5) == 0 )
- X n = 1;
- X if ( n == 0 )
- X (void) fputs(line, oldfp);
- X else
- X (void) fputs(line, tmpfp);
- X }
- X if ( ferror(mailfp) ) {
- X (void) sprintf(erline, "%s: Read failed on %s",
- X cmdname, file);
- X perror(erline);
- X rc = 1;
- X }
- X if ( !rc ) {
- X
- X /* reopen the mailbox */
- X if ( ( mailfp = freopen(file, "w", mailfp) ) == NULL ) {
- X (void) sprintf(erline, "%s: Cannot reopen %s",
- X cmdname, file);
- X perror(erline);
- X rc = 1;
- X }
- X if ( !rc ) {
- X rewind(tmpfp);
- X
- X /* copy the retained mail */
- X while ( fgets(line, PLEN, tmpfp) ) {
- X (void) fputs(line, mailfp);
- X }
- X }
- X }
- X
- X /* restore times */
- X ut.actime = st->st_atime;
- X ut.modtime = st->st_mtime;
- X (void) fclose(mailfp);
- X (void) utime(file, &ut);
- X }
- X (void) unlink(lockfile);
- X }
- X }
- X (void) fclose(tmpfp);
- X }
- X (void) fchown(fileno(oldfp), (int) st->st_uid, (int) st->st_gid);
- X (void) fclose(oldfp);
- X if ( !rc && siz_ms ) {
- X (void) sprintf(cline, MAILCMD, file);
- X
- X /* open the notification template */
- X if ( ( msfp = fopen(siz_ms, "r") ) == NULL ) {
- X (void) sprintf(erline, "%s: Cannot open %s", cmdname, siz_ms);
- X perror(erline);
- X rc = 1;
- X }
- X if ( !rc ) {
- X
- X /* open a pipe to mail */
- X if ( ( pifp = popen(cline, "w") ) == NULL ) {
- X (void) sprintf(erline, "%s: Cannot pipe to %s", cmdname, cline);
- X perror(erline);
- X rc = 1;
- X }
- X if ( !rc ) {
- X
- X /* copy with substitutions */
- X while ( fgets(line, PLEN, msfp) ) {
- X p2 = line;
- X while ( p1 = strchr(p2, '\\') ) {
- X if ( p2 = strchr(p1+1, '\\') ) {
- X (void) strcpy(tline, p2+1);
- X *p2 = '\0';
- X (void) strcpy(p1, subst(p1+1));
- X p2 = p1 + strlen(p1);
- X (void) strcat(p1, tline);
- X }
- X else break;
- X }
- X (void) fputs(line, pifp);
- X }
- X (void) pclose(pifp);
- X }
- X (void) fclose(msfp);
- X }
- X }
- X return rc;
- X}
- X
- X/* istmpnam: identify a temporary filename */
- Xistmpnam(s) char *s; {
- X int c;
- X
- X if ( !isalnum(*s) ) return FALSE;
- X while ( c = *++s )
- X if ( !isdigit(c) ) return FALSE;
- X return TRUE;
- X}
- X
- X/* fmkstemp: create and open a temp file */
- XFILE *fmkstemp(s) char *s; {
- X int n;
- X FILE *f;
- X
- X if ( ( n = mkstemp(s) ) >= 0 ) {
- X if ( f = fdopen(n, "r+") ) return f;
- X }
- X (void) sprintf(erline, "%s: Cannot create %s", cmdname, s);
- X perror(erline);
- X if ( n >= 0 ) {
- X (void) close(n);
- X (void) unlink(s);
- X }
- X return NULL;
- X}
- X
- X/* intcatch: signal handler */
- Xvoid intcatch() {
- X
- X intflag = TRUE;
- X}
- X
- X/* subst: substitute value for symbol */
- Xchar *subst(s) char *s; {
- X struct smap *sp;
- X
- X for ( sp = symtab; sp->sm_nam; ++sp ) {
- X if ( strcmp(s, sp->sm_nam) == 0 )
- X return sp->sm_val;
- X }
- X return "";
- X}
- X
- X/* save a string to allocated memory */
- Xstruct store *savestr(t, s) int t; char *s; {
- X struct store *pt;
- X static struct store *prev = NULL, *first = NULL;
- X
- X if ( t == '\0' ) return first;
- X if ( pt = (struct store *) malloc(sizeof(struct store) + strlen(s)) ) {
- X if ( first == NULL ) first = pt;
- X else prev->se_link = pt;
- X prev = pt;
- X pt->se_link = NULL;
- X pt->se_type = t;
- X (void) strcpy(pt->se_str, s);
- X }
- X else {
- X (void) fprintf(stderr, "%s: Memory allocation failed\n", cmdname);
- X }
- X return pt;
- X}
- X
- X/* print script from memory */
- Xprscript(sp) char *sp; {
- X struct store *se, *nse;
- X extern struct store *savestr();
- X
- X if ( se = savestr('\0', (char *) NULL) ) {
- X (void) printf("------cut here------\n#!/bin/sh\n");
- X do {
- X switch ( se->se_type ) {
- X case 'r':
- X (void) printf("rm -f %s/%s\n", sp, se->se_str);
- X }
- X nse = se->se_link;
- X free(se);
- X }
- X while ( se = nse );
- X (void) printf("#!/end\n");
- X }
- X}
- X
- X/**/
- SHAR_EOF
- if test 14403 -ne "`wc -c < 'mailclean.c'`"
- then
- echo shar: "error transmitting 'mailclean.c'" '(should have been 14403 characters)'
- fi
- fi
- echo shar: "extracting 'mailsize.c'" '( 4072 characters)'
- if test -f 'mailsize.c'
- then
- echo shar: "will not over-write existing file 'mailsize.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'mailsize.c'
- X/* mailsize.c: mail spool cleanup policy display and warning */
- X/* Author: Gary Mills <mills@ccu.umanitoba.ca> */
- X
- X#include <stdio.h>
- X#include <stdlib.h>
- X#include <string.h>
- X#include <errno.h>
- X#include <pwd.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X#include "defs.h"
- X
- Xchar usage[] = "Usage: %s [-v] [username]\n";
- Xint siz_tr_high = 0, siz_tr_low = 0;
- Xint siz_wa_high = 0;
- Xint vopt = FALSE; /* "verbose" option */
- X
- Xchar erline[PLEN];
- Xchar *cmdname;
- X
- X/* policy subset interpreted here */
- Xstruct pmap policy[] = {
- X { "mail-size-truncate", SIZ_TR },
- X { "mail-size-warn", SIZ_WA },
- X { NULL, 0 }
- X};
- X
- X
- Xmain(argc, argv) int argc; char *argv[]; {
- X char *spool, *op, *qpath;
- X char **qargv;
- X struct passwd *upass;
- X struct stat mbstat;
- X char mailpath[PLEN];
- X int size, qflag;
- X char *logname;
- X extern char *getlogin();
- X
- X /* parse arguments */
- X cmdname = ( cmdname = strrchr(argv[0], '/') ) ? ++cmdname : argv[0];
- X qflag = ( strcmp(cmdname, QNAME) == 0 );
- X qargv = argv;
- X while ( ++argv, --argc > 0 && *argv[0] == '-' ) {
- X for ( op = argv[0] + 1; *op; ++op ) {
- X switch ( *op ) {
- X case 'v':
- X vopt = TRUE;
- X break;
- X default:
- X (void) fprintf(stderr, usage, cmdname);
- X exit(1);
- X }
- X }
- X }
- X if ( argc > 1 ) {
- X (void) fprintf(stderr, usage, cmdname);
- X exit(1);
- X }
- X logname = NULL;
- X if ( argc == 1 ) {
- X if ( upass = getpwnam(*argv) ) {
- X if ( getuid() == upass->pw_uid || (int) getuid() == 0 ) {
- X logname = *argv;
- X }
- X else {
- X (void) fprintf(stderr, "%s: %s (uid %d): permission denied\n",
- X cmdname, *argv, upass->pw_uid);
- X exit(1);
- X }
- X }
- X else {
- X (void) fprintf(stderr, "%s: %s: unknown user\n", cmdname, *argv);
- X exit(1);
- X }
- X }
- X
- X /* initialize */
- X if ( getpolicy() != 0 )
- X exit(1);
- X if ( logname == NULL && ( logname = getlogin() ) == NULL &&
- X ( logname = getenv("LOGNAME") ) == NULL &&
- X ( logname = getenv("USER") ) == NULL ) {
- X (void) fprintf(stderr, "%s: Cannot get login name\n", cmdname);
- X exit(1);
- X }
- X qpath = QPATH;
- X spool = SPOOL;
- X (void) sprintf(mailpath, "%s/%s", spool, logname);
- X
- X /* get size of the mailbox */
- X if ( stat(mailpath, &mbstat) != 0 ) {
- X if ( errno != ENOENT ) {
- X (void) sprintf(erline, "%s: Cannot stat %s", cmdname, mailpath);
- X perror(erline);
- X exit(1);
- X }
- X size = 0;
- X }
- X else {
- X size = mbstat.st_size / 1024L;
- X }
- X
- X /* print report */
- X if ( vopt ) {
- X (void) printf("Mailbox size for %s\n", logname);
- X (void) printf("%-20s%12s%12s%12s%12s\n", "Spool", "usage", "limit",
- X "warning", "retain");
- X (void) printf("%-20s%12d%12d%12d%12d\n", spool, size, siz_tr_high,
- X siz_wa_high, siz_tr_low);
- X if ( qflag) (void) putchar('\n');
- X }
- X else if ( size > siz_wa_high ) {
- X (void) printf("Oversize mailbox in %s\n", spool);
- X if ( qflag) (void) putchar('\n');
- X }
- X if ( qflag ) {
- X
- X /* run ucb/quota */
- X (void) fflush(stdout);
- X qargv[0] = "quota";
- X (void) execv(qpath, qargv);
- X (void) sprintf(erline, "%s: Cannot exec %s", cmdname, qpath);
- X perror(erline);
- X exit(1);
- X }
- X exit(0);
- X /*NOTREACHED*/
- X}
- X
- X/* getpolicy: interpret the policy file */
- Xint getpolicy() {
- X char pline[PLEN], pverb[PLEN];
- X FILE *pfp;
- X char *pfile, *pt;
- X struct pmap *pp;
- X int n1, n2;
- X
- X pfile = PFILE;
- X if ( ( pfp = fopen(pfile, "r") ) == NULL ) {
- X (void) sprintf(erline, "%s: Cannot open %s", cmdname, pfile);
- X perror(erline);
- X return 1;
- X }
- X else {
- X while ( fgets(pline, PLEN, pfp) ) {
- X if ( ( pt = strchr(pline, '#') ) != NULL )
- X *pt = '\0';
- X if ( sscanf(pline, "%s", pverb) == 1 ) {
- X for ( pp = &policy[0]; pp->pm_verb; ++pp ) {
- X if ( strcmp(pverb, pp->pm_verb) == 0 ) {
- X switch (pp->pm_case) {
- X case SIZ_TR:
- X if ( sscanf(pline, "%*s%d%d", &n1, &n2) == 2 ) {
- X siz_tr_high = n1;
- X siz_tr_low = n2;
- X }
- X break;
- X case SIZ_WA:
- X if ( sscanf(pline, "%*s%d", &n1) == 1 ) {
- X siz_wa_high = n1;
- X }
- X break;
- X }
- X break;
- X }
- X }
- X }
- X }
- X (void) fclose(pfp);
- X }
- X return 0;
- X}
- X
- X/**/
- SHAR_EOF
- if test 4072 -ne "`wc -c < 'mailsize.c'`"
- then
- echo shar: "error transmitting 'mailsize.c'" '(should have been 4072 characters)'
- fi
- fi
- echo shar: "extracting 'mailclean.8'" '( 2850 characters)'
- if test -f 'mailclean.8'
- then
- echo shar: "will not over-write existing file 'mailclean.8'"
- else
- sed 's/^X//' << \SHAR_EOF > 'mailclean.8'
- X.TH MAILCLEAN 8 "24 August 1991"
- X.UC 4
- X.SH NAME
- Xmailclean \- clean up files in the mail spool directory
- X.SH SYNOPSIS
- X.B /usr/etc/mailclean
- X[
- X.B \-y
- X]
- X.SH DESCRIPTION
- X.B mailclean
- Xis intended to be run regularly from cron,
- Xto produce a report on standard output,
- Xand optionally take action against files in the mail spool directory.
- XIt can truncate files that are larger than some limit, saving the old
- Xmail to a temporary file, and notifying the owner by mail.
- XIt can also remove or report on files identified as being old, stray,
- Xor unsafe.
- X.LP
- X.B mailclean
- Xwithout the \-y option only reports the actions it would have taken.
- X.LP
- X.B mailclean
- Xtakes its parameters from a policy file, nominally /etc/policy.
- XThe following statements are interpreted by
- X.B mailclean :
- X.RS
- X.IP "mail-age-remove DAYS"
- Xremove mailbox files that have been unread for more than DAYS days.
- X.IP "mail-stray-remove"
- Xremove mailbox files identified as strays, meaning that the file name
- Xdoes not correspond to the login name of its owner.
- XThis operation is dangerous because it relies on correct operation of
- Xgetpwnam(3) and the integrity of /etc/passwd and the YP/NIS maps.
- X.IP "mail-stray-script"
- Xprint a shell script to remove stray files, which can be run after
- Xthe report has been examined.
- X.IP "mail-stray-report"
- Xreport mailbox files identified as strays.
- X.IP "mail-unsafe-report"
- Xreport files that are not regular files, or have a link count greater
- Xthan one.
- X.IP "mail-size-truncate KB1 KB2"
- Xtruncate mailbox files that are larger than KB1 kbytes down to KB2 kbytes,
- Xsaving the old mail to a temporary file.
- X.IP "mail-size-message FILE-NAME"
- Xwhen a file is truncated, send mail to the mailbox owner, using
- XFILE-NAME as a template.
- XThis file should contain a complete mail message, including headers.
- XVariable names, enclosed in backslashes, will be substituted into
- Xthe message, as follows:
- X.sp
- Xmailbox \- mailbox name
- X.br
- Xoldfile \- old mail file name
- X.br
- Xhsize \- mailbox high size
- X.br
- Xlsize \- mailbox low size
- X.br
- Xwsize \- mailbox warning size
- X.br
- X.IP "mail-size-report KB"
- Xreport mailbox files larger than KB kbytes.
- X.IP "mail-size-warn KB"
- X.I mailclean
- Xonly uses this for substution into the mail message, but
- X.I mailsize
- Xwill warn the owner at login time when the mailbox is larger than KB kbytes.
- X.RE
- X.LP
- XRemoval actions take precedence over truncation or scripting.
- XAll actions taken are reported.
- X.SH OPTIONS
- X.TP
- X.B \-y
- Xyes.
- XThis option is required to perform the truncate or remove operations.
- X.SH FILES
- X.PD 0
- X.TP 20
- X.B /etc/policy
- Xmail spool management parameters
- X.PD
- X.SH "SEE ALSO"
- X.BR mail(1),
- X.BR mailsize(1)
- X.SH BUGS
- XMail readers often create temporary files and lock files in the spool
- Xdirectory.
- X.B mailclean
- Xattempts to identify these and ignore them when they are recently-created.
- XUser mailboxes in the format of mktemp(3) may cause confusion.
- SHAR_EOF
- if test 2850 -ne "`wc -c < 'mailclean.8'`"
- then
- echo shar: "error transmitting 'mailclean.8'" '(should have been 2850 characters)'
- fi
- fi
- echo shar: "extracting 'mailsize.1'" '( 775 characters)'
- if test -f 'mailsize.1'
- then
- echo shar: "will not over-write existing file 'mailsize.1'"
- else
- sed 's/^X//' << \SHAR_EOF > 'mailsize.1'
- X.TH MAILSIZE 1 "24 August 1991"
- X.UC 4
- X.SH NAME
- Xmailsize \- display the size of a user's mailbox and the size limits
- X.SH SYNOPSIS
- X.B mailsize
- X[
- X.B \-v
- X] [
- X.I username
- X]
- X.SH DESCRIPTION
- X.B mailsize
- Xdisplays the size of the users' mailbox and the limits imposed by
- Xlocal policy.
- XOnly the super-user may use the optional
- X.I username
- Xargument to view the limits of users' mailboxes.
- X.LP
- X.B mailsize
- Xwithout options displays only a warning
- Xwhen the mailbox size is over the warning limit.
- XWhen invoked as
- X.B Quota ,
- X.B mailsize
- Xwill also run the
- X.B quota
- Xcommand.
- X.SH OPTIONS
- X.TP
- X.B \-v
- XDisplay the size of the mailbox and the limits on its size.
- X.SH FILES
- X.PD 0
- X.TP 20
- X.B /etc/policy
- Xmail spool management parameters
- X.PD
- X.SH "SEE ALSO"
- X.BR mail(1),
- X.BR mailclean(8),
- X.BR quota(1)
- SHAR_EOF
- if test 775 -ne "`wc -c < 'mailsize.1'`"
- then
- echo shar: "error transmitting 'mailsize.1'" '(should have been 775 characters)'
- fi
- fi
- echo shar: "extracting 'policy'" '( 230 characters)'
- if test -f 'policy'
- then
- echo shar: "will not over-write existing file 'policy'"
- else
- sed 's/^X//' << \SHAR_EOF > 'policy'
- X# policy for mailsize and mailclean
- X#
- Xmail-size-report 500
- Xmail-size-warn 750 # user login warning
- Xmail-size-truncate 1000 500
- Xmail-size-message /usr/local/etc/trunc.msg
- Xmail-age-remove 180
- Xmail-stray-script
- Xmail-unsafe-report
- SHAR_EOF
- if test 230 -ne "`wc -c < 'policy'`"
- then
- echo shar: "error transmitting 'policy'" '(should have been 230 characters)'
- fi
- fi
- echo shar: "extracting 'trunc.msg'" '( 884 characters)'
- if test -f 'trunc.msg'
- then
- echo shar: "will not over-write existing file 'trunc.msg'"
- else
- sed 's/^X//' << \SHAR_EOF > 'trunc.msg'
- XFrom: Mail Spool Cleaner <root@ccu.umanitoba.ca>
- XTo: \mailbox\
- XSubject: Oversize Unix Mailbox
- X
- XIn accord with Computer Services policy, your Unix mailbox file has
- Xbeen truncated because it was over the limit of \hsize\ kbytes. The
- Xmost recent \lsize\ kbytes (approximately) was retained, but your older
- Xmail was moved to a file \oldfile\. You can access this mail
- Xwith a command such as ``mail -f \oldfile\'', or you can move it
- Xto your home directory and give it a nicer name with a command like
- X``mv \oldfile\ ~/oldmail''. If you do nothing, this file will
- Xbe removed a week from now in the normal cleanup of the /var/tmp directory.
- X
- XTo avoid this problem in the future, you could delete unwanted mail
- Xfrom your mailbox and save mail to files in your home directory after
- Xyou have read it. You will receive a warning as you log in whenever
- Xyour mailbox exceeds \wsize\ kbytes.
- X
- SHAR_EOF
- if test 884 -ne "`wc -c < 'trunc.msg'`"
- then
- echo shar: "error transmitting 'trunc.msg'" '(should have been 884 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-
- --
- -Gary Mills- -Networking Group- -U of M Computer Services-
-
- exit 0 # Just in case...
-